#include "qcustomplottooltip.h"

#include <QToolTip>
#include <QCursor>

QCPToolTip::QCPToolTip(QCustomPlot *parent) : QCPAbstractItem(parent),
    position(createPosition(QLatin1String("position"))),
    mPlotReplot(true),
    mTextAlignment(Qt::AlignLeft | Qt::AlignVCenter),
    mRadius(6, 6),
    mSizeMode(Qt::AbsoluteSize),
    mHighlightGraph(nullptr)
{
    position->setType(QCPItemPosition::ptAbsolute);
    setSelectable(false);
    setLayer("overlay");

    setBorderPen(Qt::NoPen);
    setBrush(QColor(87, 98, 93, 180));
    setTextColor(Qt::white);
    setOffset(10, 0);
    setPadding(QMargins(6, 6, 6, 6));
    connect(mParentPlot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(handleTriggerEvent(QMouseEvent*)));
}

void QCPToolTip::setText(const QString &text)
{
    mText = text;
    //QToolTip::showText(mParentPlot->cursor().pos(), text, mParentPlot);
}

void QCPToolTip::setFont(const QFont &font)
{
    mFont = font;
}

void QCPToolTip::setTextColor(const QColor &color)
{
    mTextColor = color;
}

void QCPToolTip::setBorderPen(const QPen &pen)
{
    mBorderPen = pen;
}

void QCPToolTip::setBrush(const QBrush &brush)
{
    mBrush = brush;
}

void QCPToolTip::setRadius(double xRadius, double yRadius, Qt::SizeMode mode)
{
    mRadius.setX(xRadius);
    mRadius.setY(yRadius);
    mSizeMode = mode;
}

void QCPToolTip::setOffset(double xOffset, double yOffset)
{
    mOffset.setX(xOffset);
    mOffset.setY(yOffset);
}

void QCPToolTip::setPadding(const QMargins &paddings)
{
    mPadding = paddings;
}

void QCPToolTip::handleTriggerEvent(QMouseEvent *event)
{
    // true表示需要单独刷新, 将调用udpate函数
     updatePosition(event->pos(), true);
}

void QCPToolTip::updatePosition(const QPointF &newPos, bool replot)
{
    mHighlightGraph = nullptr;
    double tolerance = mParentPlot->selectionTolerance();

    for (int i = mParentPlot->graphCount() - 1; i >= 0; i--) {
        QCPGraph *graph = mParentPlot->graph(i);
        // graph不可见或者scatter style为空的时候, 不显示ToolTip
        if (!graph->realVisibility() || graph->scatterStyle().isNone())
            continue;

        // 用于选择的范围
        double limitDistance = tolerance;
        double penWidth = graph->pen().widthF();
        QCPScatterStyle scatterStyle = graph->scatterStyle();

        limitDistance = qMax(scatterStyle.size(), tolerance);
        penWidth = scatterStyle.isPenDefined() ? scatterStyle.pen().widthF() : penWidth;

        // details会返回最接近的一个数据点, selectTest是不精确的, 所以后面还要判断
        QVariant details;
        double currentDistance = graph->selectTest(newPos, false, &details);

        QCPDataSelection selection = details.value<QCPDataSelection>();
        if (currentDistance >= 0 && currentDistance < limitDistance + penWidth && !selection.isEmpty()) {
            // 取出当前key和value值, 并且转换成像素位置
            double key = graph->dataMainKey(selection.dataRange().begin());
            double value = graph->dataMainValue(selection.dataRange().begin());
            QPointF pos = graph->coordsToPixels(key, value);

            QRectF rect(pos.x() - limitDistance * 0.5, pos.y() - limitDistance * 0.5, limitDistance, limitDistance);
            rect = rect.adjusted(-penWidth, -penWidth, penWidth, penWidth);
            if (rect.contains(newPos)) {
                // 注释: 文字和坐标轴标签一致
                //int keyIndex = pickClosest(key, graph->keyAxis()->tickVector());
                //setText(QString("%1:%2").arg(graph->keyAxis()->tickVectorLabels().at(keyIndex), QString::number(value)));
                setText(QString("%1:%2").arg(QString::number(key), QString::number(value)));
                mHighlightGraph = graph;
                mGraphDataPos = pos;

                mParentPlot->setCursor(Qt::PointingHandCursor);
                // 更新位置
                position->setPixelPosition(newPos);
                setVisible(true);

                if (replot)
                    update();

                break;
            }
        }
    }

    if (!mHighlightGraph && visible()) {
        mParentPlot->setCursor(Qt::ArrowCursor);
        setVisible(false);
        if (replot)
            update();
    }
}

void QCPToolTip::update()
{
    // 表明单独刷新
    mPlotReplot = false;
    layer()->replot();
    // 单独刷新完成
    mPlotReplot = true;
}

double QCPToolTip::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const
{
    // 不需要鼠标点击测试, 因为ToolTip是跟随鼠标的, 鼠标点击不到
    Q_UNUSED(pos);
    Q_UNUSED(onlySelectable);
    Q_UNUSED(details);

    return -1;
}

void QCPToolTip::draw(QCPPainter *painter)
{
    // 当前是由QCustomPlot的replot函数刷新的, 所以需要更新位置
    if (mPlotReplot) {
        // false表明不刷新
        updatePosition(position->pixelPosition(), false);
        if (!visible())
            return;
    }

    drawGraphScatterPlot(painter, mHighlightGraph, mGraphDataPos);

    // 移动painter的绘制原点位置
    QPointF pos = position->pixelPosition() + mOffset;
    painter->translate(pos);

    QFontMetrics fontMetrics(mFont);
    QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | mTextAlignment, mText);
    textRect.moveTopLeft(QPoint(mPadding.left(), mPadding.top()));

    QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom());
    textBoxRect.moveTopLeft(QPoint());

    // 限制ToolTip不超过QCustomPlot的范围
    if (pos.x() + textBoxRect.width() >= mParentPlot->viewport().right())
        painter->translate(-mOffset.x() * 2 - textBoxRect.width(), 0);
    if (pos.y() + textBoxRect.height() * 2 >= mParentPlot->viewport().bottom())
        painter->translate(0, -mOffset.y() * 2 - textBoxRect.height());

    // 绘制背景和边框
    if ((mBrush != Qt::NoBrush && mBrush.color().alpha() != 0) || (mBorderPen != Qt::NoPen && mBorderPen.color().alpha() != 0)) {
        double clipPad = mBorderPen.widthF();
        QRect boundingRect = textBoxRect.adjusted(-clipPad, -clipPad, clipPad, clipPad);

        painter->setPen(mBorderPen);
        painter->setBrush(mBrush);
        painter->drawRoundedRect(boundingRect, mRadius.x(), mRadius.y(), mSizeMode);
    }

    // 绘制文字
    painter->setFont(mFont);
    painter->setPen(mTextColor);
    painter->setBrush(Qt::NoBrush);
    painter->drawText(textRect, Qt::TextDontClip | mTextAlignment, mText);

}

void QCPToolTip::drawGraphScatterPlot(QCPPainter *painter, QCPGraph *graph, const QPointF &pos)
{
    if (!graph)
        return;

    QCPScatterStyle style = graph->scatterStyle();
    if (style.isNone())
        return;

    // 如果有select decorator, 则使用修饰器的风格
    if (graph->selectionDecorator())
        style = graph->selectionDecorator()->getFinalScatterStyle(style);

    style.applyTo(painter, graph->pen());
    style.setSize(style.size() * 1.2);
    style.drawShape(painter, pos);
}

int QCPToolTip::pickClosest(double target, const QVector<double> &vector)
{
    if (vector.size() < 2)
        return 0;

    // 查找第1个 >= target的位置
    auto iter = std::lower_bound(vector.constBegin(), vector.constEnd(), target);
    if (iter == vector.constEnd())
        return vector.size() - 1;
    else if (iter == vector.constBegin())
        return 0;
    else
        return target - *(iter - 1) < *iter - target ? (iter - vector.constBegin() - 1) : (iter - vector.constBegin());
}
